package com.mrjy.payment.bo;

import com.mrjy.common.entity.TransferInfo;
import com.mrjy.common.entity.UserInfo;
import com.mrjy.maintain.dao.IUserInfoDao;
import com.mrjy.payment.dao.ITransferInfoDao;
import com.tencent.common.*;
import com.tencent.protocol.pay_protocol.TransferPayReqData;
import com.tencent.protocol.pay_protocol.TransferPayResData;
import com.tencent.protocol.refund_protocol.RefundReqData;
import com.tencent.protocol.refund_protocol.RefundResData;
import com.tencent.service.RefundService;
import com.tencent.service.TransferPayService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Javin
 * @date 2017年7月19日
 * @desc 企业付款到零钱-业务类
 * @comment ◆ 给同一个实名用户付款，单笔单日限额2W/2W ◆ 不支持给非实名用户打款 ◆ 一个商户同一日付款总额限额100W ◆ 仅支持商户号已绑定的APPID； ◆ 针对付款的目标用户，已微信支付实名认证的用户可提供校验真实姓名的功能，未实名认证的用户无法校验，企业可根据自身业务的安全级别选择验证类型； ◆ 付款金额必须小于或等于商户当前可用余额的金额；
 */
@Service("transferPaymentBo")
public class TransferPaymentBo implements ITransferPaymentBo {
	
	private static Log log = new Log(LoggerFactory.getLogger(TransferPaymentBo.class));
	
	@Resource
	private IUserInfoDao userInfoDao;
	
	@Resource
	private ITransferInfoDao transferPaymentDao;
	
	/**
	 * @author Javin
	 * @date 2017年7月19日
	 * @desc 企业付款到零钱 测试场景1：用户关注服务号==> 可以付款成功 测试场景2：用户未关注服务号==> 可以付款成功
	 * @param tranInfo
	 * @return
	 */
	@Override
	public Object weChatTransferPay(TransferInfo tranInfo){
        Map<String, Object> map = new HashMap<String, Object>();
        UserInfo userInfo = null;
        String openId = "";
        if (null == tranInfo) {
            map.put("err_code", "-1");
            map.put("err_code_des", "传入transfer对象为空");
            return map;
        } else {
            //企业付款到零钱最小金额1.00以及累积20000.00元
            if (tranInfo.getAmount().doubleValue() < 1) {
                map.put("err_code", "4001");
                map.put("err_code_des", "企业付款到零钱小于金额1.00");
                return map;
            }
            if (null != tranInfo.getUserId()) {
                Double sumAmount = transferPaymentDao.sumAmountByUserId(tranInfo.getUserId());
                if (sumAmount >= 20000) {
                    map.put("err_code", "4002");
                    map.put("err_code_des", "企业付款到累积20000.00");
                    return map;
                }
                userInfo = userInfoDao.selectUserById(tranInfo.getUserId());
                if (null != userInfo && StringUtils.isNotBlank(userInfo.getWeixinOpenid())) {
                    openId = userInfo.getWeixinOpenid();
                } else {
                    map.put("err_code", "4004");
                    map.put("err_code_des", "该用户没有openId");
                    return map;
                }
            } else {
                map.put("err_code", "4003");
                map.put("err_code_des", "用户ID为空");
                return map;
            }
        }

        TransferPayReqData reqData = new TransferPayReqData();
        reqData.setMch_appid(Configure.getAppid());
        reqData.setMchid(Configure.getMchid());
        reqData.setDevice_info("");
        reqData.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        reqData.setPartner_trade_no(tranInfo.getPartnerTradeNo());
        reqData.setOpenid(openId);
        reqData.setCheck_name("NO_CHECK");
        reqData.setRe_user_name("");
        reqData.setAmount(Integer.parseInt(Util.getMoney(tranInfo.getAmount().toString())));
        reqData.setDesc(tranInfo.getPaymentDesc());
        reqData.setSpbill_create_ip(Util.getHostIp(Util.getInetAddress()));
        reqData.setSign(Signature.getSign(reqData.toMap()));

        TransferPayService payService;
        try {
            payService = new TransferPayService();
            log.i("支付API返回的数据如下：");
            String payServiceResponseString;
            long costTimeStart = System.currentTimeMillis();
            payServiceResponseString = payService.request(reqData);
            long costTimeEnd = System.currentTimeMillis();
            log.i("api请求总耗时：" + (costTimeEnd - costTimeStart) + "ms");
            log.i(payServiceResponseString);
            TransferPayResData transferPayResData = (TransferPayResData) Util.getObjectFromXML(payServiceResponseString, TransferPayResData.class);
            if ("SUCCESS".equals(transferPayResData.getReturn_code())
                    && "SUCCESS".equals(transferPayResData.getResult_code())) {
                map.put("mchAppid", transferPayResData.getMch_appid());
                map.put("mchId", transferPayResData.getMchid());
                String timeStamp = Long.toString(new Date().getTime());
                map.put("timeStamp", timeStamp);
                map.put("nonceStr", transferPayResData.getNonce_str());
                map.put("signType", "MD5");
                map.put("partnerTradeNo", transferPayResData.getPartner_trade_no());
                map.put("paymentNo", transferPayResData.getPayment_no());
                map.put("paymentTime", transferPayResData.getPayment_time());

                String paySign = Signature.getSign(map);
                map.put("paySign", paySign);
                map.put("err_code", "200");
                map.put("err_code_des", "success");
                return map;

            } else {
                map.put("err_code", transferPayResData.getErr_code());
                map.put("err_code_des", transferPayResData.getErr_code_des());
            }
        } catch (Exception e) {
            log.e(e.getMessage());
        }

        return map;
    }

    /**
     * @param tranInfo
     * @return
     * @author Javin
     * @date 2017年7月19日
     * @desc 退款 通用
     * 注意：
     * 1、交易时间超过一年的订单无法提交退款
     * 2、微信支付退款支持单笔交易分多次退款，多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交，请不要更换退款单号，请使用原商户退款单号
     * 3、请求频率限制：150qps，即每秒钟正常的申请退款请求次数不超过150次
     * 错误或无效请求频率限制：6qps，即每秒钟异常或错误的退款申请请求不超过6次
     * 4、每个支付订单的部分退款次数不能超过50次
     */
    @Override
    public Object weChatRefundPay(TransferInfo tranInfo) {
        Map<String, Object> map = new HashMap<String, Object>();
        UserInfo userInfo = null;
        String openId = "";
        if (null == tranInfo) {
            map.put("err_code", "-1");
            map.put("err_code_des", "传入transfer对象为空");
            return map;
        } else {
            if (null != tranInfo.getUserId()) {
                Double sumAmount = transferPaymentDao.sumAmountByUserId(tranInfo.getUserId());
                if (sumAmount >= 20000) {
                    map.put("err_code", "4002");
                    map.put("err_code_des", "企业付款到累积20000.00");
                    return map;
                }
            }
        }
        RefundReqData refundReqData = new RefundReqData();
        refundReqData.setMch_id(Configure.getMchid());
        refundReqData.setDevice_info("");
        refundReqData.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        refundReqData.setOut_refund_no(tranInfo.getOutRefundNo());
        refundReqData.setTotal_fee(tranInfo.getAmount().intValue());
        refundReqData.setRefund_fee(tranInfo.getAmount().intValue());
        refundReqData.setOut_trade_no(tranInfo.getPartnerTradeNo());
        refundReqData.setAppid(Configure.getAppid());
        refundReqData.setRefund_account(tranInfo.getRefundAccount());

        refundReqData.setSign(Signature.getSign(refundReqData.toMap()));
        RefundService refundService;
        try {
            refundService = new RefundService();
            log.i("支付API返回的数据如下：");
            String payServiceResponseString;
            long costTimeStart = System.currentTimeMillis();
            payServiceResponseString = refundService.request(refundReqData);
            long costTimeEnd = System.currentTimeMillis();
            log.i("api请求总耗时：" + (costTimeEnd - costTimeStart) + "ms");
            log.i(payServiceResponseString);
            RefundResData refundResData = (RefundResData) Util.getObjectFromXML(payServiceResponseString, RefundResData.class);
            if ("SUCCESS".equals(refundResData.getReturn_code())
                    && "SUCCESS".equals(refundResData.getResult_code())) {
                map.put("mchAppid", refundResData.getAppid());
                map.put("mchId", refundResData.getMch_id());
                String timeStamp = Long.toString(new Date().getTime());
                map.put("timeStamp", timeStamp);
                map.put("nonceStr", refundResData.getNonce_str());
                map.put("signType", "MD5");
                map.put("out_trade_no", refundResData.getOut_trade_no());
                map.put("refund_id", refundResData.getRefund_id());
                map.put("refund_fee", refundResData.getRefund_fee());
                map.put("out_refund_no", refundResData.getOut_refund_no());
                String paySign = Signature.getSign(map);
                map.put("paySign", paySign);
                map.put("err_code", "200");
                map.put("err_code_des", "success");
                return map;

            } else {
                map.put("err_code", refundResData.getErr_code());
                map.put("err_code_des", refundResData.getErr_code_des());
            }
        } catch (Exception e) {
            log.e(e.getMessage());
        }

        return map;
    }
}
